package org.anachronos.jeep.ui.trace;

import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.MultiList;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ICellEditorValidator;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.widgets.FormToolkit;

public class TraceTablePage extends TraceBasePage {
	private final TraceFilter traceFilter = new TraceFilter();
	private TableViewer tableViewer;
	private Object input;
	private TraceViewerSorter sorter;

	public TraceTablePage(final FormEditor editor, final String id, final String title) {
		super(editor, id, title);
	}

	protected void createFormContent(final IManagedForm managedForm) {
		final GridDataFactory gridDataFactory = 
			GridDataFactory.swtDefaults().align(SWT.FILL, SWT.FILL).grab(true, true);

		final Composite body = managedForm.getForm().getBody();
		body.setLayout(new GridLayout(1, false));
		body.setLayoutData(gridDataFactory.create());
		final FormToolkit formToolkit = managedForm.getToolkit();
		final Composite tableParent = formToolkit.createComposite(body, SWT.NONE);
		final TableColumnLayout tableColumnLayout = new TableColumnLayout();
		tableParent.setLayout(tableColumnLayout);
		tableParent.setLayoutData(gridDataFactory.create());

		final Table table = formToolkit.createTable(tableParent, SWT.NONE);
		table.setHeaderVisible(true);
		final TraceLabelProvider labelProvider = new TraceLabelProvider();
		tableViewer = new TableViewer(table);
		
		final TableColumn nameColumn = createViewerColumn(tableViewer, "Name", SWT.LEFT, TraceFilterParser.NAME)
			.getColumn();
		tableColumnLayout.setColumnData(nameColumn, new ColumnWeightData(35));
		
		final TableColumn invocationColumn = createViewerColumn(tableViewer, "Invocation", SWT.LEFT, TraceFilterParser.NAME)
			.getColumn();
		tableColumnLayout.setColumnData(invocationColumn, new ColumnWeightData(40));

		final TableColumn selfMsColumn = createViewerColumn(tableViewer, "Self[ms]", SWT.RIGHT, TraceFilterParser.NUMERIC)
			.getColumn();
		tableColumnLayout.setColumnData(selfMsColumn, new ColumnWeightData(10));
		final TableColumn selfPercentColumn = createViewerColumn(tableViewer, "Self[%]", SWT.RIGHT, TraceFilterParser.NUMERIC)
			.getColumn();
		table.setSortColumn(selfPercentColumn);
		table.setSortDirection(SWT.DOWN);
		tableColumnLayout.setColumnData(selfPercentColumn, new ColumnWeightData(7));

		final TableColumn totalMsColumn = createViewerColumn(tableViewer, "Total[ms]", SWT.RIGHT, TraceFilterParser.NUMERIC)
			.getColumn();
		tableColumnLayout.setColumnData(totalMsColumn, new ColumnWeightData(10));
		final TableColumn totalPercentColumn = createViewerColumn(tableViewer, "Total[%]", SWT.RIGHT, TraceFilterParser.NUMERIC)
			.getColumn();
		tableColumnLayout.setColumnData(totalPercentColumn, new ColumnWeightData(7));

		final TableColumn callsColumn = createViewerColumn(tableViewer, "Calls", SWT.RIGHT, TraceFilterParser.NUMERIC)
			.getColumn();
		tableColumnLayout.setColumnData(callsColumn, new ColumnWeightData(10));

		tableViewer.setContentProvider(new ObservableListContentProvider());
		tableViewer.setLabelProvider(labelProvider);
		tableViewer.setFilters(new ViewerFilter[] {traceFilter});
		tableViewer.setInput(input);
		sorter = new TraceViewerSorter();
		tableViewer.setSorter(sorter);
		
		registerContextMenu(tableViewer);
	}

	public void setInput(final Object input) {
		if (tableViewer != null) {
			final MultiList multiList = wrapInput(input);
			tableViewer.setInput(multiList);
		} else {
			final MultiList multiList = wrapInput(input);
			this.input = multiList;
		}
	}

	private MultiList wrapInput(final Object input) {
		final IObservableList observableList = (IObservableList) input;
		final ViewerFilterObservableList traceFilterObservableList = new ViewerFilterObservableList(traceFilter);
		final IObservableList[] observableLists = 
			new IObservableList[] {observableList, traceFilterObservableList};
		final MultiList multiList = new MultiList(observableLists);
		return multiList;
	}

	private TableColumn createColumn(final Table table,
			final String columnName, final int style) {
		final TableColumn column = new TableColumn(table, style);
		column.setText(columnName);
		column.addSelectionListener(new SelectionListener() {			
			@Override
			public void widgetSelected(SelectionEvent e) {
				final TableColumn column = (TableColumn) e.widget;
				final int sortDirection;
				if (table.getSortColumn() == column) {
					switch (table.getSortDirection()) {
					case SWT.UP:
						sortDirection = SWT.DOWN;
						break;
					default:
						sortDirection = SWT.UP;
					}
				} else {
					table.setSortColumn(column);
					sortDirection = table.getSortDirection();
				}
				table.setSortDirection(sortDirection);
				final int indexOf = table.indexOf(column);
				sorter.setSortColumnIndex(indexOf);
				sorter.setSortDirection(sortDirection);
				tableViewer.refresh();
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});
		return column;
	}

	private TableViewerColumn createViewerColumn(final TableViewer tableViewer,
			final String columnName, final int style, final ICellEditorValidator cellEditorValidator) {
		final TableColumn column = createColumn(tableViewer.getTable(), columnName, style);
		final TableViewerColumn viewerColumn = new TableViewerColumn(tableViewer, column);
		viewerColumn.setLabelProvider(new TraceLabelProvider());
		viewerColumn.setEditingSupport(new TraceFilterEditingSupport(tableViewer, cellEditorValidator));
		return viewerColumn;
	}
	
	@Override
	public Viewer getViewer() {
		return tableViewer;
	}
}
